package com.huawo.opensdk.utils;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.schedulers.Schedulers;

public class UploadFileUtils {


    public static String parsePath(String path) {
        if (!TextUtils.isEmpty(path)) {
            if (!path.toLowerCase().startsWith("http")) {
//                return "https://static.huawo-wear.com/files/" + path;
                return "https://test.huawo-wear.com/files/" + path;
            }
        }
        return path;
    }

    public static Single<ByteBuffer> downloadFile(String url) {
        return Single.<ByteBuffer>create(emitter -> {
            try {
                Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : url = " + url);
                HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
//                connection.setRequestProperty("Connection", "close");
                try {
                    // 部分实现忽略timeout属性，需要由外部的rxjava来控制超时
                    Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : connect -> begin");
                    Log.i("UploadFileUtils", "【UploadFileUtils】 获取请求头 :\n" + getReqeustHeader(connection));
                    connection.setConnectTimeout(60 * 1000);     //连接超时 60s
                    connection.setReadTimeout(60 * 1000);      // 读取超时  60s
                    connection.connect();
                    Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : connect -> end");
                    int responseCode = connection.getResponseCode();
                    Log.i("UploadFileUtils", "【UploadFileUtils】 responseCode :" + responseCode);
                    Log.i("UploadFileUtils", "【UploadFileUtils】 获得响应头 :\n" + getResponseHeader(connection));
                    if (HttpURLConnection.HTTP_OK != responseCode) {
                        throw new IllegalStateException("responseCode = " + responseCode);
                    }

                    try (InputStream inputStream = connection.getInputStream()) {
                        Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : readStream -> begin");
                        byte[] bytes = StreamUtils.copyToByteArray(inputStream);
                        Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : readStream -> end : " + bytes.length);
                        emitter.onSuccess(ByteBuffer.wrap(bytes));
                    } catch (Exception e) {
                        Log.e("UploadFileUtils", "【UploadFileUtils】 downloadFile catch error", e);
                        emitter.onError(e);
                    }
                } finally {
                    connection.disconnect();
                }
            } catch (Exception e) {
                Log.e("UploadFileUtils", "【UploadFileUtils】 downloadFile catch error", e);
                emitter.onError(e);
            }
        }).subscribeOn(Schedulers.io());
    }

    public interface ProgressListener {
        void onProgress(long bytesRead, long contentLength, float progress);
    }
    public static Single<ByteBuffer> downloadFile(String url, ProgressListener progressListener) {
        return Single.create((SingleOnSubscribe<ByteBuffer>) emitter -> {
            HttpURLConnection connection = null;
            try {
                connection = (HttpURLConnection) new URL(url).openConnection();
                connection.setConnectTimeout(60 * 1000);
                connection.setReadTimeout(60 * 1000);
                connection.connect();

                int responseCode = connection.getResponseCode();
                if (HttpURLConnection.HTTP_OK != responseCode) {
                    throw new IllegalStateException("Response code: " + responseCode);
                }

                long contentLength = 0;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    contentLength = connection.getContentLengthLong();
                }
                InputStream inputStream = new BufferedInputStream(connection.getInputStream());

                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                long totalBytesRead = 0;

                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, bytesRead);
                    totalBytesRead += bytesRead;

                    float progress = (float) totalBytesRead / contentLength;
                    progressListener.onProgress(totalBytesRead, contentLength, (float)(Math.round(progress * 100)) / 100);
                }

                byte[] bytes = byteArrayOutputStream.toByteArray();
                emitter.onSuccess(ByteBuffer.wrap(bytes));
            } catch (Exception e) {
                emitter.onError(e);
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }).subscribeOn(Schedulers.io());
    }

    //读取请求头
    private static String getReqeustHeader(HttpURLConnection conn) {
        Map<String, List<String>> requestHeaderMap = conn.getRequestProperties();
        Iterator<String> requestHeaderIterator = requestHeaderMap.keySet().iterator();
        StringBuilder sbRequestHeader = new StringBuilder();
        while (requestHeaderIterator.hasNext()) {
            String requestHeaderKey = requestHeaderIterator.next();
            String requestHeaderValue = conn.getRequestProperty(requestHeaderKey);
            sbRequestHeader.append(requestHeaderKey);
            sbRequestHeader.append(":");
            sbRequestHeader.append(requestHeaderValue);
            sbRequestHeader.append("\n");
        }
        return sbRequestHeader.toString();
    }

    //读取响应头
    private static String getResponseHeader(HttpURLConnection conn) {
        Map<String, List<String>> responseHeaderMap = conn.getHeaderFields();
        int size = responseHeaderMap.size();
        StringBuilder sbResponseHeader = new StringBuilder();
        for (int i = 0; i < size; i++) {
            String responseHeaderKey = conn.getHeaderFieldKey(i);
            String responseHeaderValue = conn.getHeaderField(i);
            sbResponseHeader.append(responseHeaderKey);
            sbResponseHeader.append(":");
            sbResponseHeader.append(responseHeaderValue);
            sbResponseHeader.append("\n");
        }
        return sbResponseHeader.toString();
    }

    public static Observable<Float> downloadFile(String fileUrl, String savePath) {
        return Observable.<Float>create(emitter -> {
            try {
                Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : url = " + fileUrl);
                HttpURLConnection connection = (HttpURLConnection) new URL(fileUrl).openConnection();
//                connection.setRequestMethod("GET");
//                connection.setDoOutput(true);
                Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : connect -> begin");
                Log.i("UploadFileUtils", "【UploadFileUtils】 获取请求头 :\n" + getReqeustHeader(connection));
                connection.connect();
                int responseCode = connection.getResponseCode();
                Log.i("UploadFileUtils", "【UploadFileUtils】 responseCode :" + responseCode);
                Log.i("UploadFileUtils", "【UploadFileUtils】 获得响应头 :\n" + getResponseHeader(connection));
                if (HttpURLConnection.HTTP_OK != responseCode) {
                    throw new IllegalStateException("responseCode = " + responseCode);
                }
                int fileLength = connection.getContentLength();
                Log.i("UploadFileUtils", "【UploadFileUtils】 fileLength :" + fileLength);
                // 读取数据并写入到byte数组，同时更新下载进度
                try (InputStream inputStream = connection.getInputStream()) {
                    FileOutputStream output = new FileOutputStream(savePath);
                    byte[] buffer = new byte[1024];
                    int len;
                    int totalRead = 0;
                    Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : readStream -> begin");
                    while ((len = inputStream.read(buffer)) != -1) {
                        // 写入数据到byte数组
                        output.write(buffer, 0, len);
                        // 更新下载进度
                        totalRead += len;
                        float progress = ((float) totalRead / fileLength);
                        emitter.onNext(progress);
                    }
                    output.flush();
                    output.close();
                    inputStream.close();
                    emitter.onComplete();
                    Log.i("UploadFileUtils", "【UploadFileUtils】 downloadFile : readStream -> success : ");
                } catch (Exception e) {
                    Log.e("UploadFileUtils", "【UploadFileUtils】 downloadFile catch error", e);
                    emitter.onError(e);
                }


            } catch (Exception e) {
                Log.e("UploadFileUtils", "【UploadFileUtils】 downloadFile catch error", e);
                emitter.onError(e);
            }
        }).subscribeOn(Schedulers.io());
    }

    public static byte[] readFile(File file) {
        RandomAccessFile rf = null;
        byte[] data = null;
        try {
            rf = new RandomAccessFile(file, "r");
            data = new byte[(int) rf.length()];
            rf.readFully(data);
        } catch (Exception exception) {
            exception.printStackTrace();
        } finally {
            closeQuietly(rf);
        }
        return data;
    }

    public static void closeQuietly(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /**
     * check NetworkAvailable
     *
     * @param context
     * @return
     */
    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager manager = (ConnectivityManager) context.getApplicationContext().getSystemService(
                Context.CONNECTIVITY_SERVICE);
        if (null == manager)
            return false;
        NetworkInfo info = manager.getActiveNetworkInfo();
        if (null == info || !info.isAvailable())
            return false;
        return true;
    }

}
